package fr.umlv.m2.jee.spij.service.tutorial.impl;

import fr.umlv.m2.jee.spij.persistence.actor.StudentTutorial;
import fr.umlv.m2.jee.spij.persistence.actor.TeacherTutorial;
import fr.umlv.m2.jee.spij.persistence.actor.dao.HibernateStudentTutorialDAO;
import fr.umlv.m2.jee.spij.persistence.actor.dao.HibernateTeacherTutorialDAO;
import fr.umlv.m2.jee.spij.persistence.education.Tutorial;
import fr.umlv.m2.jee.spij.persistence.education.Unit;
import fr.umlv.m2.jee.spij.persistence.education.dao.HibernateTutorialDAO;
import fr.umlv.m2.jee.spij.persistence.education.dao.HibernateUnitDAO;
import fr.umlv.m2.jee.spij.service.ldap.authentification.DisplayActor;
import fr.umlv.m2.jee.spij.service.tutorial.DisplayTutorial;
import fr.umlv.m2.jee.spij.service.tutorial.IDisplayTutorialService;
import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.binding.message.MessageBuilder;
import org.springframework.binding.message.MessageContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author thomas magny
 * @author mathieu mazzolini
 */
@Service("defaultDisplayTutorialService")
public class DefaultDisplayTutorialService implements IDisplayTutorialService {

    @Autowired
    private HibernateTutorialDAO tutorialDAO;

    @Autowired
    private HibernateStudentTutorialDAO studentTutorialDAO;

    @Autowired
    private HibernateTeacherTutorialDAO teacherTutorialDAO;

    @Autowired
    private HibernateUnitDAO unitDAO;

    /**
     *
     */
    public DefaultDisplayTutorialService() {
    }

    /**
     * @param unitId
     * @param context
     *
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public List<DisplayTutorial> getAllDisplayTutorial(long unitId, MessageContext context) {
        Unit unit = unitDAO.findById(unitId);

        final List<Tutorial> tutorials = unit.getTutorials();
        final List<DisplayTutorial> displayTutorials = new ArrayList<DisplayTutorial>();

        if (tutorials == null) {
            context.addMessage(new MessageBuilder().error().code("tutorials.empty").build());
        } else {
            for (Tutorial tutorial : tutorials) {
                DisplayTutorial displayTutorial = new DisplayTutorial(tutorial);

                displayTutorial.setUnit(unitId);
                displayTutorial.setUnitName(unit.getName());

                displayTutorials.add(displayTutorial);
            }
        }
        return displayTutorials;
    }

    /**
     * @param unitId      the unit foreign key
     * @param currentUser
     * @param context
     *
     * @return
     */
    @Transactional(readOnly = true)
    @Override
    public List<DisplayTutorial> getAllDisplayTutorialPerUser(final long unitId, DisplayActor currentUser, MessageContext context) {
        if (currentUser.isTeacher() || currentUser.isStudent()) {
            Unit unit = unitDAO.findById(unitId);

            final List<Tutorial> tutorials = tutorialDAO.findByLdapActorAndUnitId(unitId, currentUser.getLogin(), currentUser.getType());
            final List<DisplayTutorial> displayTutorials = new ArrayList<DisplayTutorial>();

            if (tutorials == null) {
                context.addMessage(new MessageBuilder().error().code("tutorials.empty").build());
            } else {
                for (Tutorial tutorial : tutorials) {
                    DisplayTutorial displayTutorial = new DisplayTutorial(tutorial);
                    displayTutorial.setUnit(unitId);
                    displayTutorial.setUnitName(unit.getName());

                    displayTutorials.add(displayTutorial);
                }
            }
            return displayTutorials;
        }

        return getAllDisplayTutorial(unitId, context);
    }

    /**
     * @param id
     * @param context
     *
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public DisplayTutorial getTutorialById(long id, MessageContext context) {
        Tutorial tutorial = tutorialDAO.findById(id);
        if (tutorial == null) {
            context.addMessage(new MessageBuilder().error().code("tutorial.empty").build());
            return null;
        }

        return new DisplayTutorial(tutorial);
    }

    /**
     * @param displayTutorial
     * @param unitId
     * @param context
     *
     * @return
     */
    @Override
    @Transactional(readOnly = false)
    public boolean createTutorial(DisplayTutorial displayTutorial,
                                  long unitId, MessageContext context) {
        Tutorial tutorial = new Tutorial();
        tutorial.setSubject(displayTutorial.getSubject());
        tutorial.setContain(displayTutorial.getContain());
        tutorial.setCorrection(displayTutorial.getCorrection());

        Date date = displayTutorial.getDate();

        DateTime startTime = new DateTime(date.getTime());
        startTime = startTime.plus(displayTutorial.getStartTime().getTime());

        DateTime endTime = new DateTime(date.getTime());
        endTime = endTime.plus(displayTutorial.getEndTime().getTime());

        if (startTime.isAfter(endTime)) {
            context.addMessage(new MessageBuilder().error().code("tutorial.startTime.isAfter.endTime").build());
            return false;
        }

        Interval duration = new Interval(startTime, endTime);

        tutorial.setDuration(duration);
        tutorial.setLinkSupport(displayTutorial.getLinkSupport());
        tutorial.setLinkCorrection(displayTutorial.getLinkCorrection());

        tutorial.setUnit(unitId);

        tutorialDAO.persist(tutorial);

        return true;
    }

    /**
     * @param id
     *
     * @return
     */
    @Override
    @Transactional(readOnly = false)
    public boolean deleteTutorialById(long id) {
        Tutorial tutorial = tutorialDAO.findById(id);
        List<StudentTutorial> students = tutorial.getStudents();
        for (StudentTutorial studentTutorial : students) {
            studentTutorialDAO.remove(studentTutorial);
            studentTutorialDAO.flush();
        }
        List<TeacherTutorial> teachers = tutorial.getTeachers();
        for (TeacherTutorial teacherTutorial : teachers) {
            teacherTutorialDAO.remove(teacherTutorial);
            teacherTutorialDAO.flush();
        }

        tutorialDAO.remove(tutorial);
        tutorialDAO.flush();
        return true;
    }

    /**
     * @param modifiedTutorial
     * @param context
     *
     * @return
     */
    @Override
    @Transactional(readOnly = false)
    public boolean updateTutorialById(DisplayTutorial modifiedTutorial, MessageContext context) {
        Tutorial tutorial = tutorialDAO.findById(modifiedTutorial.getId());
        boolean hasBeenModified = false;

        if (tutorial != null) {
            if (!tutorial.getSubject().equals(modifiedTutorial.getSubject())) {
                hasBeenModified = true;
                tutorial.setSubject(modifiedTutorial.getSubject());
            }
            if (!tutorial.getContain().equals(modifiedTutorial.getContain())) {
                hasBeenModified = true;
                tutorial.setContain(modifiedTutorial.getContain());
            }
            if (!tutorial.getCorrection().equals(modifiedTutorial.getCorrection())) {
                hasBeenModified = true;
                tutorial.setCorrection(modifiedTutorial.getCorrection());
            }
            if (!tutorial.getLinkSupport().equals(modifiedTutorial.getLinkSupport())) {
                hasBeenModified = true;
                tutorial.setLinkSupport(modifiedTutorial.getLinkSupport());
            }
            if (!tutorial.getLinkCorrection().equals(modifiedTutorial.getLinkCorrection())) {
                hasBeenModified = true;
                tutorial.setLinkCorrection(modifiedTutorial.getLinkCorrection());
            }

            // Duration update
            Date date = modifiedTutorial.getDate();
            DateTime startTime = new DateTime(date.getTime());
            startTime = startTime.plus(modifiedTutorial.getStartTime().getTime());

            DateTime endTime = new DateTime(date.getTime());
            endTime = endTime.plus(modifiedTutorial.getEndTime().getTime());

            DateTime previousStartDate = tutorial.getDuration().getStart();
            DateTime previousEndDate = tutorial.getDuration().getEnd();

            if (startTime.isAfter(endTime)) {
                context.addMessage(new MessageBuilder().error().code("tutorial.startTime.isAfter.endTime").build());
                return false;
            }

            if (!previousStartDate.equals(startTime) || !previousEndDate.equals(endTime)) {
                hasBeenModified = true;
                tutorial.setDuration(new Interval(startTime, endTime));
            }
            tutorialDAO.merge(tutorial);
        }

        if (!hasBeenModified) {
            context.addMessage(new MessageBuilder().error().code("updateTutorialFail").build());
        }

        return hasBeenModified;
    }
}
